package cn.com.captureNetPacket;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

import cn.com.captureNetPacket.dao.ConfigInfoMapper;
import cn.com.captureNetPacket.dao.DeviceInfoMapper;
import cn.com.captureNetPacket.dao.RecordLogMapper;
import cn.com.captureNetPacket.model.ConfigData;
import cn.com.captureNetPacket.model.ConfigInfo;
import cn.com.captureNetPacket.model.DeviceInfo;
import cn.com.captureNetPacket.util.RedisConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

@Slf4j
@Component
@EnableScheduling
public class CaptureNetPacketService {
	// 标识config 程序
	public static final int appId=1;
	
	@Autowired
	private RecordLogMapper recordLogMapper;
	 
	private static RecordLogMapper recLogMapper;
	private static String currentRecordUri;

	public static RecordLogMapper getRecLogMapper() {
		return recLogMapper;
	}
	
	@Autowired
	private DeviceInfoMapper deviceMapper;
	 @Value("${cnp.clusterServerId}")
	private String clusterServerId;

	 @Value("${cnp.announceIp}")
	private String announceIp;
	 @Value("${cnp.announcePort}")
	private String announcePort;

	 @Value("${server.port}")
	private String serverPort;
	 @Value("${server.servlet.context-path}")
	private String contextPath;

	 private static String clusterServId;
	@Autowired
	private ConfigInfoMapper configInfoMapper;
	@Autowired
	private ObjectMapper objMapper;
	
	public static String getClusterServId() {
		return clusterServId;
	}
	public final static DateTimeFormatter tempFileDF = DateTimeFormatter.ofPattern("yyyy_MM_dd_HH_mm_ss_SSSSSS");
	public final static DateTimeFormatter fileDF = DateTimeFormatter.ofPattern("yyyy_MM_dd_HH_mm_ss");
	public final static DateTimeFormatter dirDF = DateTimeFormatter.ofPattern("yyyyMMdd");
	public  static Properties props;
 
	 
	public void showSystemPlatformInfo() {
		 InetAddress addr; String ip= null,hostName= null;
		try {
			props = System.getProperties();
			addr = InetAddress.getLocalHost();
			   ip = addr.getHostAddress().toString(); //获取本机ip
	           hostName = addr.getHostName().toString(); //获取本机计算机名称
			if(!StringUtils.hasText(announceIp)){
				announceIp=ip;
			}
			if(!StringUtils.hasText(announcePort)){
				announcePort=serverPort;
			}
		} catch (UnknownHostException e) {
		log.error("showSystemPlatformInfo：",e);
		}
         
			log.info("本机IP：{} \n 本机名称:{}",ip, hostName);
			log.info("Java的运行环境版本：{}" , props.getProperty("java.version"));
	        log.info("Java的运行环境供应商：{}", props.getProperty("java.vendor"));
	        log.info("Java供应商的URL：{}", props.getProperty("java.vendor.url"));
	        log.info("Java的安装路径：{}", props.getProperty("java.home"));
	        log.info("Java的虚拟机规范版本：{}", props.getProperty("java.vm.specification.version"));
	        log.info("Java的虚拟机规范供应商：{}", props.getProperty("java.vm.specification.vendor"));
	        log.info("Java的虚拟机规范名称：{}", props.getProperty("java.vm.specification.name"));
	        log.info("Java的虚拟机实现版本：{}", props.getProperty("java.vm.version"));
	        log.info("Java的虚拟机实现供应商：{}", props.getProperty("java.vm.vendor"));
	        log.info("Java的虚拟机实现名称：{}", props.getProperty("java.vm.name"));
	        log.info("Java运行时环境规范版本：{}", props.getProperty("java.specification.version"));
	        log.info("Java运行时环境规范供应商：{}", props.getProperty("java.specification.vender"));
	        log.info("Java运行时环境规范名称：{}", props.getProperty("java.specification.name"));
	        log.info("Java的类格式版本号：{}", props.getProperty("java.class.version"));
	        log.info("Java的类路径：{}", props.getProperty("java.class.path"));
	        log.info("加载库时搜索的路径列表：{}", props.getProperty("java.library.path"));
	        log.info("默认的临时文件路径：{}", props.getProperty("java.io.tmpdir"));
	        log.info("一个或多个扩展目录的路径：{}", props.getProperty("java.ext.dirs"));
	        log.info("操作系统的名称：{}", props.getProperty("os.name"));
	        log.info("操作系统的构架：{}", props.getProperty("os.arch"));
	        log.info("操作系统的版本：{}", props.getProperty("os.version"));
	        log.info("文件分隔符：{}", props.getProperty("file.separator"));
	        //在 unix 系统中是＂／＂
	        log.info("路径分隔符：{}", props.getProperty("path.separator"));
	        //在 unix 系统中是＂:＂
	        log.info("行分隔符：{}", props.getProperty("line.separator"));
	        //在 unix 系统中是＂/n＂
	        log.info("用户的账户名称：{}", props.getProperty("user.name"));
	        log.info("用户的主目录：{}", props.getProperty("user.home"));
	        log.info("用户的当前工作目录：{}", props.getProperty("user.dir"));
	 
	}
 
	private void initStaticConfig() throws Exception {
		 
		recLogMapper=recordLogMapper;
		 
//		 config=configData;


		 
		 List<ConfigInfo> listParameter=configInfoMapper.readParameters();
		 if(listParameter.size()<1) {
			 throw new Exception(" 没有读取到任何参数信息，请检查配置。");
		 }
		 
		 log.debug("读取到的参数 列表:{}",listParameter);
		 readConfig(listParameter);
	}
	
	  public   ConfigData readConfig(List<ConfigInfo> listParameter) {
		  ConfigData configData=new ConfigData();
		  for (ConfigInfo configInfo : listParameter) {
			  RedisConfig.setPermanentValue("ConfigData:"+configInfo.getClusterServId()+":"+configInfo.getName(), configInfo.getValue());
			  try {
				log.debug(" #### ---> ConfigInfo :{}",objMapper.writeValueAsString(configInfo));
			} catch (JsonProcessingException e) {
				 log.warn("readDeviceInfos 读取失败clusterServerId: {} ,parameterName: {} value: {}",configInfo.getClusterServId(),configInfo.getName(), configInfo.getValue());
			}
			   }
		  return configData;
		  } 
	  
	  
	  
	  Map <String,DeviceInfo> oldDeviceInfos=new HashMap<String, DeviceInfo>();
	  public   boolean readDeviceInfos() {
		  boolean isChange= false ;
		  List<DeviceInfo> deviceInfos=deviceMapper.queryDeviceInfo();
		  Set<String> deviceNumbers=deviceInfos.stream().map(DeviceInfo -> DeviceInfo.getDeviceNumber()).collect(Collectors.toSet());
		  // 移除掉没哟逇
//		  if(oldDeviceInfos.keySet()!=null)
//		  for (String oldDeviceNumber : oldDeviceInfos.keySet()) {
//			  if(!deviceNumbers.contains(oldDeviceNumber))
//			  {
//			oldDeviceInfos.remove(oldDeviceNumber);
//			  RedisConfig.deleteValue("DeviceInfo:"+oldDeviceNumber);
//			  log.debug("DeviceInfo: {} isdeleted",oldDeviceNumber);
//			  isChange=true;
//			  } 
//		}
		  Iterator<String> odil=oldDeviceInfos.keySet().iterator();
		  while (odil.hasNext()) {
			  String oldDeviceNumber =odil.next();
			  if(!deviceNumbers.contains(oldDeviceNumber))
			  {
			  RedisConfig.deleteValue("DeviceInfo:"+oldDeviceNumber);
			  odil.remove();
			  log.debug("DeviceInfo: {} isdeleted",oldDeviceNumber);
			  isChange=true;
			  } 
			
		}
		  
		  
		  DeviceInfo oldDeviceInfo;
		 for (DeviceInfo deviceInfo : deviceInfos) {
			  try {
				  if(deviceInfo.getAlias()==null) deviceInfo.setAlias("");
				  if(deviceInfo.getMac()==null) deviceInfo.setMac("");
				  if(deviceInfo.getIp()==null)deviceInfo.setIp("");
				  if(oldDeviceInfos.size()<1) {
				RedisConfig.setPermanentValue("DeviceInfo:"+deviceInfo.getDeviceNumber(),  objMapper.writeValueAsString(deviceInfo));
				isChange=true;
				log.debug("device {} is change  \r\noldDeviceInfo {}",objMapper.writeValueAsString(deviceInfo),objMapper.writeValueAsString(deviceInfo));
				}
				 else {
					 oldDeviceInfo=oldDeviceInfos.get(deviceInfo.getDeviceNumber());
					 
					 // 判断是否变化
					 if(oldDeviceInfo==null || !oldDeviceInfo.getIp().equals(deviceInfo.getIp()) || !oldDeviceInfo.getMac().equals(deviceInfo.getMac()) || (oldDeviceInfo.isNeedRecord()!=deviceInfo.isNeedRecord())
							 || (oldDeviceInfo.isNprtd()!=deviceInfo.isNprtd()) || (oldDeviceInfo.isPrttda()!=deviceInfo.isPrttda())) {
						 RedisConfig.setPermanentValue("DeviceInfo:"+deviceInfo.getDeviceNumber(),  objMapper.writeValueAsString(deviceInfo));
						 log.debug("device {} is change  \r\noldDeviceInfo {}",objMapper.writeValueAsString(deviceInfo),objMapper.writeValueAsString(oldDeviceInfo));
						 
						 isChange=true;
					 }
				  }
				  oldDeviceInfos.put(deviceInfo.getDeviceNumber(), deviceInfo);
//				log.debug("DeviceInfo is add:{}",objMapper.writeValueAsString(deviceInfo));
			} catch (JsonProcessingException e) {
				 log.warn("readDeviceInfos 读取失败  DeviceInfo DeviceNumber: {}",deviceInfo.getDeviceNumber());
			}
		}
		 	return isChange;
	  } 
	
	public void publishReloadConfig() {
		ObjectNode  message=	objMapper.createObjectNode();
		message.put("clusterServId",clusterServId);
		message.put("command","reloadAppData");
		RedisConfig.publishMessage("config", message);
	}
	public void publishReloadDeviceInfoChange() {
		ObjectNode  message=	objMapper.createObjectNode();
		message.put("clusterServId",clusterServId);
		message.put("command","reloadDeviceInfo");
		RedisConfig.publishMessage("config", message);
	}
	
	@Scheduled(initialDelay = 1000,fixedDelay =180*1000)
	public void scheduledTask() {
		publishDownloadInfo();
		 if(readDeviceInfos())
			 publishReloadDeviceInfoChange();
	 
	}
	public boolean  checkDeviceInfo() {
		publishReloadDeviceInfoChange();
		return false;
	}
	
	public void startinit() throws Exception {
		clusterServId=clusterServerId;

		showSystemPlatformInfo();
		initStaticConfig();
		readDeviceInfos();


		publishReloadDeviceInfoChange();
		 publishReloadConfig();
	}


	public void publishDownloadInfo(){
		log.info("当前集群节点ID(clusterServId)为: {} 对外IP(announceIp): {} uri:{}{}",clusterServId,announceIp,serverPort,contextPath);
		currentRecordUri=announceIp+":"+serverPort+contextPath;
		RedisConfig.setValue("recordUri:"+announceIp,currentRecordUri,600000);

		Set<String> keys=RedisConfig.getkeys("recordUri:");
		if(keys!=null) {
			keys.forEach( key-> {
						log.info("已添加的录音的uri key-> {} uri: {}", key,RedisConfig.getRealKeyValue(key));
					}
			);
		}
	}



	public static String getCurrentRecordUri(){
			return currentRecordUri;
	}
}
